// 以插件的形式定义
export default function install(Vue, options){
    let uri_map = {};
    let err_code = {};
    let defConf = Object.assign({
        method: 'get',  //默认请求方式
        dataType: 'json',
        cache: false,
        fresh: true,
        credentials: true,  //是否开启跨域携带  cookie
        debug: false,
        apiCache: {},
        timeout: 10000,
        autoNotify:  true  //是否自动弹出提示
    }, options);

    let requestQueue = [];

    // 入栈
    function pushQueue(stack, key, val){
        stack[key] = stack[key]||[];
        stack[key].push(val);
    }

    // 出栈
    function spliceQueue(stack, val){
        let index = stack.indexOf(val);
        if(index>-1) stack.splice(index, 1);
    }

    function parseQuery(query){
        return Object.keys(query).map(key=>{
            return `${key}=${query[key]}`;
        }).join('&');
    }

    // query 处理
    function addQuery(config, qs){
        let query = qs||config.query;
        let url = config.url;
        query = parseQuery(query);
        if(url.includes('?')){
            config.url+='&'+query;
        }else{
            config.url+='?'+query;
        }
    }

    // 返回了一个 request 方法
    var request = (function(){
        let defHeaders = {
            'X-Requested-With': 'XMLHttpRequest'
        };

        let entId = getCookie('ent_id');
        if(entId){
            defHeaders['X-Ent-ID'] = entId;
        }

        // 这就是闭包，每次都返回一个 Promise
        function request(config){
            let  me = this;
            let xhr = new XMLHttpRequest();
            let req = new Promise((resolve, reject)=>{
                // 有个默认配置的合并，应该是 request 有 request 的默认配置，全局有全局的默认配置
                let rawConfig = Object.assign({},  defConf, config);
                config.headers = Object.assign({}, defHeaders, config.headers);
                //短链到完整个 url 的拼接
                if(uri_map[config.url]){
                    config.url = uri_map[config.url];
                }
                // 自动判断是否 跨域
                // 此处可以对请求进行拦截操作
                let method = config.method.toLowerCase();
                let dataType = config.dataType.toLowerCase();
                let headers = config.headers;
                // 跨域 要自动判断？
                // let crossOrigin = url 的域名
                // 处理url，params 和 query
                if(config.params){
                    // 目前接口中包括了动态参数和给 query 的参数
                }
                // 这个版本是带入了缓存功能
                if(config.query){
                    addQuery(config);
                }

                xhr.open(method, config.url, true);

                if(crossorigin){
                    if(config.credentials) xhr.withCredentials = true;
                    // 这个头为什么要删除？
                    delete headers['X-Requested-With'];
                }

                // 设置公共请求头
                Object.keys(headers).forEach(key=>{
                    xhr.setRequestHeader(key, headers[key]);
                });

                if(config.timeout){
                    xhr.timeout = config.timeout;
                }

                // 请求过程
                xhr.onload = function(e){
                    // 请求结束了，出栈
                    spliceQueue(requestQueue[currentLocation], this);
                    if(this.status>=200 && this.status<300|| this.status==304){
                        let value = this.responseText;
                        // 查看字段中有无缓存处理
                        if(dataType=='json'){
                            try{
                                value = JSON.parse(value);
                            }catch(e){
                                // 数据有问题 
                                reject(e);
                                return
                            }
                        }
                        // 这就是为啥 axios 做通用的工具，你加 filter 就行了
                        // 请求成功和失败都要打点
                        if(value && value.success){
                            resolve(value.result||{});
                        }else{
                            if(config.autoNotify){
                                if(err_code){
                                    let tip = err_code[value.code]||  value.message;
                                    // 调用全局 toast，进行提示
                                    // 这个地方是不是应该设为公共方法
                                }
                                reject(value||{});
                            }else{
                                //将 code 和 提示给回去
                                if(err_code){
                                    let tip = err_code[value.code]||  value.message;
                                    let obj = {...(value||  {}), tip};
                                    reject(obj);
                                }
                            }
                        }
                    } else{
                        reject(e);
                    }
                }

                // 超时、出错
                xhr.ontimeout = xhr.onerror = function(e){
                    // 此队列不应该以当前页面为准(route.name为准？) 
                    spliceQueue(requestQueue[currentLocation], this);
                    reject(e);
                }

                // 请求取消，出栈，取消任务
                xhr.onabort = function(){
                    spliceQueue(requestQueue[currentLocation], this);
                    reject({
                        type: 'abort'
                    })
                }

                // 上传进度
                xhr.upload.onprogress = function(e){
                    if(e.lengthComputable){
                        xhr.progressHandler && xhr.progressHandler(e.loaded, e.total);
                    }
                }

                xhr.send();
                // 请求发送后，进入队列
                pushQueue(me, '_requestQueue', xhr)
                pushQueue(requestQueue, currentLocation, xhr);
            });  

            // 对 xhr 的请求，挂在 promise 上
            req.abort = function(){
                xhr.abort();
            }

            // 链式调用
            req.progress = function(cb){
                xhr.progressHandler = cb;
                return this;
            }
            
            return req;
        }

        return request;
    })();
}